# Copyright (c) 2019 Presto Labs Pte. Ltd.
# Author: zijin

import datetime
import traceback
import os

import pandas as pd

from coin.base.query_util import query_pta
from python.coin.strategy.basis_strat.analysis.report_og_log_analysis import *

FLAGS = flags.FLAGS


def fetch_strategy_summary(start, end):
  start_date = datetime.datetime.strptime(start, '%Y%m%d')
  end_date = datetime.datetime.strptime(end, '%Y%m%d') - datetime.timedelta(1)
  strategy_summary = query_pta(start_date=start_date,
                               end_date=end_date,
                               business_units=['Coin'],
                               pta_type='STRATEGY')
  return strategy_summary


def get_group(strategy_name):
  if strategy_name.startswith('basis'):
    if strategy_name.startswith('basis_model'):
      return 'basis_model'
    elif strategy_name.startswith('basis_smm2_dmm'):
      return 'basis_smm2_dmm'
    elif strategy_name.startswith('basis_smm2'):
      return 'basis_smm2'
  elif strategy_name.startswith('mm'):
    if strategy_name.startswith('mm_portfolio'):
      return 'mm_portfolio'
    elif strategy_name.startswith('mm_currency_premium'):
      return 'mm_currency_premium'
    elif strategy_name.startswith('mmrev'):
      return 'mmrev'
  elif strategy_name.startswith('lm'):
    if strategy_name.startswith('lm_volume'):
      return 'lm-volume'
    elif strategy_name.startswith('lm_focus'):
      if strategy_name.startswith('lm_focus_st'):
        return 'lm-focus-st'
      elif strategy_name.startswith('lm_focus_volume'):
        return 'lm-focus-volume'
      elif strategy_name.startswith('lm_focus_dm'):
        return 'lm-focus-dm'
      else:
        return 'lm-focus'
    elif strategy_name.startswith('lm_agg2'):
      if strategy_name.startswith('lm_agg2_highstack'):
        return 'lm-agg2-highstack'
      else:
        return 'lm-agg2'
  elif strategy_name.startswith('dmm2'):
    return 'dmm2'
  elif strategy_name.startswith('umm'):
    return 'umm'
  elif strategy_name.startswith('vmm'):
    return 'vmm'
  elif strategy_name.startswith('midfreq_longshort'):
    return 'midfreq_longshort'
  elif strategy_name.startswith('midfreq_longonly'):
    return 'midfreq_longonly'
  elif strategy_name.startswith('lowfreq_longshort'):
    return 'lowfreq_longshort'
  elif strategy_name.startswith('midfreq_hedged'):
    return 'midfreq_hedged'
  elif strategy_name.startswith('midfreq_double'):
    return 'midfreq_double'
  elif strategy_name.startswith('midfreq_volume'):
    return 'midfreq_volume'
  elif strategy_name.startswith('midfreq_portfolio'):
    return 'midfreq_portfolio'
  elif strategy_name.startswith('model_smm'):
    return 'model_smm'
  elif strategy_name.startswith('model_portfolio'):
    return 'model_portfolio'
  elif strategy_name.startswith('model_volume'):
    return 'model_volume'
  else:
    print(strategy_name)
    raise ValueError("Invalid strategy group")


def convert_pnl_to_usd(pnl_summary, end_date):
  ccy_list = pnl_summary['accounting_currency']
  query_date = (datetime.datetime.strptime(end_date, '%Y%m%d') - datetime.timedelta(days=1)).date()
  rate_list = query_exchange_rates(ccy_list, 'USD', query_date)
  usd_multiplier = {ccy: rate for ccy, rate in zip(ccy_list, rate_list)}
  pnl_summary['usd_multiplier'] = pd.Series(
      [usd_multiplier[ccy] for ccy in pnl_summary['accounting_currency']])
  pnl_summary['fill_pnl'] = pnl_summary['pnl_by_fill'] * pnl_summary['usd_multiplier']
  return pnl_summary


def combine_and_compare(pnl_summary, pta_strategy_summary):
  if pta_strategy_summary is None:
    raise ValueError("No pta pnls.")
  for i in range(len(pnl_summary)):
    strategy_name = pnl_summary.loc[i, 'strategy_name']
    curr = pnl_summary.loc[i, 'accounting_currency']
    this_row = pta_strategy_summary.loc[(pta_strategy_summary['strategy_name'] == strategy_name) &
                                        (pta_strategy_summary['accounting_currency'] == curr)]
    if len(this_row) > 0:
      pnl_summary.loc[i, 'pnl_by_balance'] = float(this_row['pnl_mark_from_balance_in_usd'].sum())
      pnl_summary.loc[i, 'pta_pnl'] = float(this_row['pnl_mark_in_usd'].sum())
    pnl_summary['%diff'] = abs(
        1 - pnl_summary['pnl_by_balance'].divide(pnl_summary['pnl_by_fill'])) * 100
    pnl_summary['abs_diff'] = abs(pnl_summary['fill_pnl'] - pnl_summary['pta_pnl'])
  return pnl_summary.dropna(subset=['pnl_by_balance'])


def verify_strat_pnl(start, end):
  pta_strategy_summary = fetch_strategy_summary(start, end).reset_index()
  report_pnl_path = os.path.join(FLAGS.csv_output_dir, 'pnl_summary_%s.csv' % start)
  assert os.path.exists(report_pnl_path)
  pnl_summary = pd.read_csv(report_pnl_path)
  pnl_summary['strategy_group'] = [get_group(name) for name in pnl_summary['strategy_name']]
  pnl_summary = convert_pnl_to_usd(pnl_summary, end)
  pnl_summary = combine_and_compare(pnl_summary, pta_strategy_summary)
  group_pnl_summary = pnl_summary.groupby(pnl_summary['strategy_group'])[['fill_pnl',
                                                                          'pta_pnl']].sum()
  group_pnl_summary['%diff'] = abs(
      1 - group_pnl_summary['pta_pnl'].divide(group_pnl_summary['fill_pnl'])) * 100
  return pnl_summary, group_pnl_summary


def main(argv):
  start = get_start_date()
  end = get_end_date(start)
  try:
    tmp_dir_file = sorted(glob.glob('tmp/daily_report_tmp_dir_*.txt'))[-1]
    with open(tmp_dir_file, 'r') as f:
      tmp_output_dir = f.readline()
      assert (os.path.exists(tmp_output_dir))
  except:
    raise ValueError("Cannot fetch daily report pnls.")

  FLAGS.csv_output_dir = os.path.join(tmp_output_dir, FLAGS.csv_output_dir)
  try:
    summary, group_summary = verify_strat_pnl(start, end)
  except Exception as e:
    name = 'Failed Verify Pnl %s' % start
    text = '%s' % (traceback.format_exc())
    print(name)
    print(text)
    print(e)
    send_mail(name, FLAGS.from_mail, FLAGS.error_mail, name, text)

  name = "combined_pnl_summary_%s.csv" % start
  csv_output_path = os.path.join(tmp_output_dir, FLAGS.csv_output_dir, name)
  summary.sort_values(by=['strategy_name']).to_csv(csv_output_path, index=False)
  pd.options.display.max_colwidth = 200
  additionl_msg = summary.sort_values(by=['abs_diff'],
                                      ascending=False).iloc[:min(10, len(summary))][[
                                          'strategy_name', 'fill_pnl', 'pta_pnl', 'abs_diff'
                                      ]].round(3).to_string(index=False)
  group_summary_name = "group_pnl_summary_%s.txt" % start
  group_summary_output_path = os.path.join(tmp_output_dir, FLAGS.csv_output_dir, group_summary_name)
  with open(group_summary_output_path, 'w') as f:
    f.write(group_summary.round(3).to_string())
  if FLAGS.report_slack:
    try:
      sh = SlackHelper('.', 'team_u_ops')
      sh.send_slack_noti(group_summary.round(3).to_string(), None, True)
      sh.send_slack_noti(additionl_msg, None, True)
    except:
      traceback.print_exc()
  send_mail_with_attachments("Pnl Summary %s" % start, FLAGS.from_mail, FLAGS.to_mail, name,
                             summary, csv_output_path)


if __name__ == '__main__':
  flags.DEFINE_string('start_date', '', '')
  flags.DEFINE_string('end_date', '', '')
  flags.DEFINE_string('csv_output_dir', 'verify_pnl', '')
  flags.DEFINE_string('from_mail', 'basis_strategy@joomo.io', '')
  flags.DEFINE_string('to_mail', 'zijin@prestolabs.io', '')
  flags.DEFINE_string('error_mail', '', '')
  flags.DEFINE_bool('report_slack', False, '')
  app.run(main)
